﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dycox.Workflows
{
    public struct ComponentIdentifier
    {

        public static readonly ComponentIdentifier Empty = new ComponentIdentifier();

        private Guid _processId;

        public Guid ProcessId
        {
            get { return _processId; }
            set { _processId = value; }
        }

        private short? _threadId;

        public short? ThreadId
        {
            get { return _threadId; }
            set { _threadId = value; }
        }

        private short? _stepSequence;

        public short? StepSequence
        {
            get { return _stepSequence; }
            set { _stepSequence = value; }
        }

        public bool IsEmpty
        {
            get { return _processId == Guid.Empty && _threadId == null && _stepSequence == null; }
        }

        public ComponentIdentifier(Guid processId)
        {
            _processId = processId;
            _stepSequence = _threadId = null;
        }

        public ComponentIdentifier(Guid processId, short threadId)
        {
            _processId = processId;
            _threadId = threadId;
            _stepSequence = null;
        }

        public ComponentIdentifier(Guid processId, short threadId, short sequence)
        {
            _processId = processId;
            _threadId = threadId;
            _stepSequence = sequence;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(_processId.ToString("N"));
            if (_threadId != null)
            {
                sb.Append(_threadId.Value.ToString("X4"));
                if (_stepSequence != null)
                {
                    sb.Append(_stepSequence.Value.ToString("X4"));
                }
            }
            return sb.ToString();
        }

        public static ComponentIdentifier Parse(string text)
        {
            if (text == null)
                throw new ArgumentNullException("text");

            ComponentIdentifier id;

            if (TryParse(text, out id))
                return id;

            throw new FormatException(string.Format("\"{0}\" is not a valid ComponentIdentifier value.", text));
        }

        public static bool TryParse(string text, out ComponentIdentifier value)
        {
            value = new ComponentIdentifier();

            if (!string.IsNullOrWhiteSpace(text))
            {
                int length = text.Length;

                if (length == 32 || length == 36 || length == 40)
                {
                    Guid guid;

                    if (Guid.TryParse(text.Substring(0, 32), out guid))
                    {
                        bool ok = false;

                        if (length >= 36)
                        {
                            short tid;
                            if (short.TryParse(text.Substring(32, 4), System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.CurrentCulture, out tid))
                            {
                                if (length == 40)
                                {
                                    short seq;
                                    if (short.TryParse(text.Substring(36, 4), System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.CurrentCulture, out seq))
                                    {
                                        value = new ComponentIdentifier(guid, tid, seq);
                                        ok = true;
                                    }
                                }
                                else
                                {
                                    value = new ComponentIdentifier(guid, tid);
                                    ok = true;
                                }
                            }
                        }
                        else
                        {
                            value = new ComponentIdentifier(guid);
                            ok = true;
                        }

                        return ok;
                    }
                }
            }

            return false;

        }

        // override object.Equals
        public override bool Equals(object obj)
        {
            //       
            // See the full list of guidelines at
            //   http://go.microsoft.com/fwlink/?LinkID=85237  
            // and also the guidance for operator== at
            //   http://go.microsoft.com/fwlink/?LinkId=85238
            //

            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            ComponentIdentifier other = (ComponentIdentifier)obj;
            return other._processId == this._processId && other._stepSequence == this._stepSequence && other._threadId == this._threadId;
        }

        // override object.GetHashCode
        public override int GetHashCode()
        {
            return _processId.GetHashCode() ^ _stepSequence.GetHashCode() ^ _threadId.GetHashCode();
        }
    }
}
